package mymyoux.io
{
	import flash.errors.IOError;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.Socket;
	import flash.utils.ByteArray;
	import flash.utils.clearTimeout;
	import flash.utils.setTimeout;
	
	import mymyoux.debug.Log;
	
	import org.osflash.signals.Signal;
	public class SimpleSocket
	{
		public static const MIN_PORT:uint = 1;
		public static const MAX_PORT:uint = 65535;

		protected var _socket:flash.net.Socket;
		protected var _dataSignal:Signal;
		protected var _connexionSignal:Signal;
		protected var _blockedDataSignal:Signal;
		protected var port:int;
		protected var ip:String;
		protected var _timeout:uint;
		protected var timer:int;
		
		protected var _mode:String;
		public function SimpleSocket(socket:flash.net.Socket = null)
		{
			timer = -1;
			timeout = 5000;
			this.socket = socket;
			_dataSignal = new Signal(ByteArray);
			_connexionSignal = new Signal(Boolean);
			_blockedDataSignal = new Signal();
			if(socket != null && socket.connected)
			{
				_connexionSignal.dispatch(true);
			}
			 
		}

		public function get canWrite():Boolean
		{
			return _socket != null && _socket.connected;
		}
		public function writeObject(object:Object):void
		{
			if(canWrite)
			{
				try
				{
					_socket.writeObject(object);
					_socket.flush();
				}catch(error:IOError)
				{
					_blockedDataSignal.dispatch(object);
				}
				
			}else
			{
				_blockedDataSignal.dispatch(object);
			}
		}
		public function writeString(object:String):void
		{
			if(canWrite)
			{
				try
				{
					_socket.writeUTFBytes(object+"\r\n");
					_socket.flush();
				}catch(error:IOError)
				{
					_blockedDataSignal.dispatch(object);
				}
				
			}else
			{
				_blockedDataSignal.dispatch(object);
			}
		}

		public function writeBytes(object:ByteArray):void
		{
			if(canWrite)
			{
				try
				{
					_socket.writeBytes(object,0,object.length);
					_socket.flush();
				}catch(error:IOError)
				{
					_blockedDataSignal.dispatch(object);
				}
				
			}else
			{
				_blockedDataSignal.dispatch(object);
			}
		}
		public function get timeout():uint
		{
			return _timeout;
		}
		public function set timeout(value:uint):void
		{
			_timeout = value; 
			if(timer > -1 && _timeout == 0)
			{
				flash.utils.clearTimeout(timer);
				timer = -1;
			}
			if(socket != null && !socket.connected && timer == -1)
			{
				if(_timeout > 0)
				{
					timer = flash.utils.setTimeout(endTimer,timeout);
				}
			}
			
		}
		public function get socket():flash.net.Socket
		{
			return _socket;
		}
		public function set socket(value:flash.net.Socket):void
		{
			if(_socket != null)
			{
				close();
				_socket.removeEventListener(Event.CLOSE,onClose);
				_socket.removeEventListener(Event.CONNECT,onConnect);
				_socket.removeEventListener(IOErrorEvent.IO_ERROR,onError);
				_socket.removeEventListener(SecurityErrorEvent.SECURITY_ERROR,onError);
				_socket.removeEventListener(ProgressEvent.SOCKET_DATA,onData);
			}
			_socket = value;
			if(_socket != null)
			{
				_socket.addEventListener(Event.CLOSE,onClose);
				_socket.addEventListener(Event.CONNECT,onConnect);
				_socket.addEventListener(IOErrorEvent.IO_ERROR,onError);
				_socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR,onError);
				_socket.addEventListener(ProgressEvent.SOCKET_DATA,onData);
			}
			ip = null;
			timer = -1;
		}
		public function close():void
		{
			try
			{
				if(_socket != null)
				{
					_socket.flush();
					_socket.close();
				}
			}catch(error:IOError)
			{
				Log.error(error);
			}
		}
		public function get blockedDataSignal():Signal
		{
			return _blockedDataSignal;
		}
		public function createSocket(ip:String, port:uint):void
		{
			if(port >= MIN_PORT && port <= MAX_PORT)
			{
				this.socket = new flash.net.Socket();
				this.socket.connect(ip,port);
				this.ip = ip;
				this.port = port;
				if(timeout > 0)
				{
					timer = flash.utils.setTimeout(endTimer,timeout);
				}
			}else
			{
				_connexionSignal.dispatch(false);
			}	
		}		
		protected function endTimer():void
		{
			if(!socket.connected)
			{
				timer = -1;
				_connexionSignal.dispatch(false);
			}
		}
		public function get dataSignal():Signal
		{
			return _dataSignal;
		}
		public function get connexionSignal():Signal
		{
			return _connexionSignal;
		}
		protected function onData(event:ProgressEvent):void
		{
			 try
			 {
			 	var b:ByteArray = new ByteArray();
			 	socket.readBytes(b,0,socket.bytesAvailable);
			 	 _dataSignal.dispatch(b);
			 }catch(error:Error)
			 {
			 	
			 }
		}
		protected function onClose(event:Event):void
		{
		//	Log.warn("close");
			if(ip != null && timeout > 0)
			{
				_socket.connect(ip, port);
				if(timer == -1)
				{
					timer = flash.utils.setTimeout(endTimer,timeout);
				}
			}else
			{
				_connexionSignal.dispatch(false);
			}
		}
		protected function onConnect(event:Event):void
		{
			_connexionSignal.dispatch(true);
			if(timer > 0)
			{
				flash.utils.clearTimeout(timer);
				timer = -1;
			}
			
		}
		protected function onError(event:Event):void
		{
			Log.warn("error : " +event);
			if(ip != null && timeout > 0)
			{
				_socket.connect(ip, port);
				if(timer == -1)
				{
					timer = flash.utils.setTimeout(endTimer,timeout);
				}
			}else
			{
				_connexionSignal.dispatch(false);
			}
		}
	}
}